package com.dkd.manage.service.impl;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.dkd.common.constant.DkdContants;
import com.dkd.common.core.domain.AjaxResult;
import com.dkd.common.exception.ServiceException;
import com.dkd.common.utils.DateUtils;
import com.dkd.manage.domain.Dto.TaskDetailsDto;
import com.dkd.manage.domain.Dto.TaskDto;
import com.dkd.manage.domain.Emp;
import com.dkd.manage.domain.TaskDetails;
import com.dkd.manage.domain.VendingMachine;
import com.dkd.manage.domain.Vo.TaskVo;
import com.dkd.manage.service.IEmpService;
import com.dkd.manage.service.IVendingMachineService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.dkd.manage.mapper.TaskMapper;
import com.dkd.manage.domain.Task;
import com.dkd.manage.service.ITaskService;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.rowset.serial.SerialException;

/**
 * 工单Service业务层处理
 * 
 * @author dcg
 * @date 2025-07-18
 */
@Service
public class TaskServiceImpl implements ITaskService 
{
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private IVendingMachineService  vendingMachineService;
    @Autowired
    private IEmpService empService;
    @Autowired
    private RedisTemplate  redisTemplate;

    @Autowired
    private TaskDetailsServiceImpl taskDetailsService;

    /**
     * 查询工单
     * 
     * @param taskId 工单主键
     * @return 工单
     */
    @Override
    public Task selectTaskByTaskId(Long taskId)
    {
        return taskMapper.selectTaskByTaskId(taskId);
    }

    /**
     * 查询工单列表
     * 
     * @param task 工单
     * @return 工单
     */
    @Override
    public List<Task> selectTaskList(Task task)
    {
        return taskMapper.selectTaskList(task);
    }

    /**
     * 新增工单
     * 
     * @param task 工单
     * @return 结果
     */
    @Override
    public int insertTask(Task task)
    {
        task.setCreateTime(DateUtils.getNowDate());
        return taskMapper.insertTask(task);
    }

    /**
     * 修改工单
     * 
     * @param task 工单
     * @return 结果
     */
    @Override
    public int updateTask(Task task)
    {
        task.setUpdateTime(DateUtils.getNowDate());
        return taskMapper.updateTask(task);
    }

    /**
     * 批量删除工单
     * 
     * @param taskIds 需要删除的工单主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskIds(Long[] taskIds)
    {
        return taskMapper.deleteTaskByTaskIds(taskIds);
    }

    /**
     * 删除工单信息
     * 
     * @param taskId 工单主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskId(Long taskId)
    {
        return taskMapper.deleteTaskByTaskId(taskId);
    }


    /**
     * 查询工单列表
     *
     * @param task 工单
     * @return 工单集合
     */
    @Override
    public List<TaskVo> selectTaskListAndTaskType(Task task) {
        return taskMapper.selectTaskListAndTaskType(task);
    }


    /**
     *  新增工单
     * @param taskDto
     * @return 影响行数
     */
    @Override
    @Transactional
    public int insertTaskDto(TaskDto taskDto) {
        // 1.查询该设备是否存在
        VendingMachine vendingMachine = vendingMachineService.selectByInnerCode(taskDto.getInnerCode());
        if (vendingMachine == null) {
            throw  new ServiceException("设备不存在");
        }
        // 2.判断工单不可以进行创建的情况
        checkCreateTask(vendingMachine.getVmStatus(),taskDto.getProductTypeId());
        // 3.检查设备是否有同类型的工单正在处理
        checkDuplicateTask(taskDto);
        // 4.检查员工是否存在
        Emp emp = empService.selectEmpById(taskDto.getUserId());
        if (emp == null) {
            throw new ServiceException("员工不存在");
        }
        // 5.检查是否同一个区域
        if (!emp.getRegionId().equals(vendingMachine.getRegionId())){
            throw new ServiceException("员工所属区域不一致，无法处理此工单");
        }
        // 6.dto转为po
        Task task = BeanUtil.copyProperties(taskDto, Task.class);
        // 工单的状态
        task.setTaskStatus(DkdContants.TASK_STATUS_CREATE);
        // 执行人的名字
        task.setUserName(emp.getUserName());
        // 工单在的区域
        task.setRegionId(emp.getRegionId());
        // 工单的地址
        task.setAddr(vendingMachine.getAddr());
        // 工单的创建时间
        task.setCreateTime(DateUtils.getNowDate());
        // 工单的编号
        task.setTaskCode(generateTaskCode());
        // 将工单进行插入
        int result= taskMapper.insertTask(task);
        // 7.判断是否为补货的工单，要把补货的详情持久化进数据库
        if(taskDto.getProductTypeId().equals(DkdContants.TASK_TYPE_SUPPLY)){
            // 8.获取补货工单的详情
            List<TaskDetailsDto> details = taskDto.getDetails();
            // 补货的详情是不可为空的
            if(details==null||details.size()==0){
                throw new ServiceException("补货工单的详情不可为空！");
            }
            // 存在详情，就进行持久化
            List<TaskDetails> taskDetailsList = details.stream().map(taskDetailsDto -> {
                TaskDetails taskDetails = BeanUtil.copyProperties(taskDetailsDto, TaskDetails.class);
                taskDetails.setTaskId(task.getTaskId());
                return taskDetails;
            }).collect(Collectors.toList());
            // 批量插入工单详情
            taskDetailsService.batchInsertTaskDetails(taskDetailsList);
        }
        return result;
    }

    private String generateTaskCode(){
        // 生成的是年月日yyyyMMdd
        String dateStr = DateUtils.getDate().replace("-", "");
        // redis的键值
        String redisKey = "taskCode:" + dateStr;
        // 如果key不存在
        if (!redisTemplate.hasKey(redisKey)){
            // 创建并设初始值为1，并且存在过期时间
            redisTemplate.opsForValue().set(redisKey, 1, Duration.ofDays(1));
            return  dateStr +"0001";
        }
        // 如果存在，自增即可
        return dateStr+StrUtil.padPre(redisTemplate.opsForValue().increment(redisKey).toString(), 4, "0");
    }

    private void checkCreateTask(Long vmStatus,Long productTypeId){
        // 投放的工单，设备不可能二次投放，异常
        if (productTypeId == DkdContants.TASK_TYPE_DEPLOY && vmStatus == DkdContants.VM_STATUS_RUNNING){
            throw new ServiceException("设备运行，无法二次投放！");
        }
        // 维修的工单，设备不运行（不存在），异常
        if (productTypeId == DkdContants.TASK_TYPE_REPAIR && vmStatus != DkdContants.VM_STATUS_RUNNING){
            throw new ServiceException("设备未运行，无法进行维修！");
        }
        // 补货的工单，设备不运行（不存在），异常
        if (productTypeId == DkdContants.TASK_TYPE_SUPPLY && vmStatus != DkdContants.VM_STATUS_RUNNING){
            throw new ServiceException("设备未运行，无法进行补货！");
        }
        // 撤机的工单，设备不运行（不存在），异常
        if (productTypeId == DkdContants.TASK_TYPE_REVOKE && vmStatus != DkdContants.VM_STATUS_RUNNING){
            throw new ServiceException("设备未运行，无法进行撤机！");
        }
    }
    private void checkDuplicateTask(TaskDto taskDto) {
        // 构建需要检查的状态列表：待办（已创建）和进行中
        List<Long> processingStatuses = Arrays.asList(
                DkdContants.TASK_STATUS_CREATE,  // 待办（已创建）
                DkdContants.TASK_STATUS_PROGRESS  // 进行中
        );

        // 调用Mapper查询是否存在冲突工单
        List<Task> taskList = taskMapper.selectTasksByStatuses(
                taskDto.getInnerCode(),
                taskDto.getProductTypeId(),
                processingStatuses
        );
        if (taskList != null && !taskList.isEmpty()) {
            throw new ServiceException("同类型工单正在处理，无法重复！");
        }
    }
}
